package org.lex.utils.logging;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;

import org.lex.utils.SystemProperties;
import org.lex.utils.text.DateTimeUtilities;


public class MyFormatter extends Formatter {
	private String newline = null;
	private Date date = null;
	private DateFormat timeFormatter = null;

	public MyFormatter() {
		super();
		this.newline = SystemProperties.lineSeparator();
		this.date = new Date();
		this.timeFormatter = DateTimeUtilities.getDateTimeFormat(DateFormat.DEFAULT, DateFormat.DEFAULT);
	}

	public synchronized String format(LogRecord record) {
		StringBuilder buffer = new StringBuilder();
		// time
		date.setTime(record.getMillis());
		buffer.append(timeFormatter.format(date));
		buffer.append(' ');
		// class name
		if (record.getSourceClassName() != null) {
			buffer.append(record.getSourceClassName());
			// method name
			if (record.getSourceMethodName() != null) {
				buffer.append('.');
				buffer.append(record.getSourceMethodName());
				buffer.append('(').append(')');
			}
		} else {
			buffer.append(record.getLoggerName());
			// method name
			if (record.getSourceMethodName() != null)
				buffer.append(record.getSourceMethodName());
		}
		buffer.append(newline);
		// level name
		buffer.append(record.getLevel());
		buffer.append(':').append(' ');
		// message
		String message = tinyFormatMessage(record);
		buffer.append(message);
		buffer.append(newline);
		// thrown
		if (record.getThrown() != null) {
			try {
				StringWriter sw = new StringWriter();
				PrintWriter pw = new PrintWriter(sw);
				record.getThrown().printStackTrace(pw);
				pw.close();
				buffer.append(sw.toString());
			} catch (Exception ex) {
			}
		}
		return buffer.toString();
	}

	public synchronized String tinyFormatMessage(LogRecord record) {
		String format = record.getMessage();
		try {
			Object parameters[] = record.getParameters();
			if (parameters == null || parameters.length == 0) {
				// No parameters. Just return format string.
				return format;
			}
			// Is is a java.text style format?
			// Ideally we could match with
			// Pattern.compile("\\{\\d").matcher(format).find())
			// However the cost is 14% higher, so we cheaply check for
			// 1 of the first 4 parameters
			if (format.indexOf("{0") >= 0 || format.indexOf("{1") >= 0 || format.indexOf("{2") >= 0 || format.indexOf("{3") >= 0) {
				return MessageFormat.format(format, parameters);
			}
			return format;

		} catch (Exception ex) {
			// Formatting failed: use localized format string.
			return format;
		}
	}
}
